package com.luckzj.sec.bridge;

import com.luckzj.sec.config.BridgeConfig;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * Log inbound and outbound packages
 */
public class PackageLoggingBridge extends AbstractBridge{
    private static Logger logger = LoggerFactory.getLogger(PackageLoggingBridge.class);

    public PackageLoggingBridge(BridgeConfig bridgeConfig) {
        super(bridgeConfig);
    }

    @Override
    protected void setupServerChannel(SocketChannel ch) {
        ch.pipeline().addFirst(new LoggingInboundHandler(), new LoggingOutboundHandler());
    }

    @Override
    protected void setupClientChannel(SocketChannel ch) {
        ch.pipeline().addFirst(new LoggingInboundHandler(), new LoggingOutboundHandler());
    }

    /**
     *
     */
    public class LoggingInboundHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            byte[] data = readBytes(msg);
            Channel ch = ctx.channel();

            writeLog(ch.remoteAddress(), ch.localAddress(), data);

            super.channelRead(ctx, msg);
        }
    }

    /**
     *
     */
    public class LoggingOutboundHandler extends ChannelOutboundHandlerAdapter {
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            byte[] data = readBytes(msg);
            Channel ch = ctx.channel();

            writeLog(ch.localAddress(), ch.remoteAddress(), data);

            super.write(ctx, msg, promise);
        }

    }

    private byte[] readBytes(Object msg) {
        byte[] data;

        if (msg instanceof ByteBuf) {
            ByteBuf byteBuf = (ByteBuf)msg;
            data = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(data);
            byteBuf.resetReaderIndex();
        }
        else {
            data = msg.toString().getBytes(StandardCharsets.UTF_8);
        }

        return data;
    }

    protected void writeLog(SocketAddress from, SocketAddress to, byte[] msg)
            throws UnsupportedEncodingException {
        String logmsg = new String(msg, "UTF-8");

        InetSocketAddress ifrom = (InetSocketAddress)from;
        InetSocketAddress ito = (InetSocketAddress)to;

        String log = String.format("%s:%d->%s:%d %s"
                , ifrom.getHostString(), ifrom.getPort(), ito.getHostString(), ito.getPort(), logmsg);

        logger.info(log);
    }
}
